package com.ys.filelib.filedialog;

import android.os.Environment;

import com.ys.filelib.filedialog.util.MyLog;

import java.io.File;
import java.math.RoundingMode;
import java.net.FileNameMap;
import java.net.URLConnection;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.Set;

/**
 *
 */

public class FileUtil {

    // 1024
    private static final long KB = 1L << 10;
    private static final long MB = 1L << 20;
    private static final long GB = 1L << 30;
    private static final long TB = 1L << 40;
    private static final long PB = 1L << 50;
    private static final long EB = 1L << 60;

    // 1000
    private static final long KB_1 = 1000L;
    private static final long MB_1 = KB_1 * KB_1;
    private static final long GB_1 = MB_1 * KB_1;
    private static final long TB_1 = GB_1 * KB_1;
    private static final long PB_1 = TB_1 * KB_1;
    private static final long EB_1 = PB_1 * KB_1;


    public static final int FILE_AUDIO = 11;
    public static final int FILE_VIDEO = 12;
    public static final int FILE_IMAGE = 13;
    public static final int FILE_WEBP = 14;
    public static final int FILE_GIF = 15;
    public static final int FILE_RAR = 16;
    public static final int FILE_ZIP = 17;
    public static final int FILE_TAR = 18;
    public static final int FILE_JAR = 19;
    public static final int FILE_APK = 20;
    public static final int FILE_TEXT = 21;
    public static final int FILE_SCRIPT = 22;
    public static final int FILE_WORD = 25;
    public static final int FILE_PPT = 26;
    public static final int FILE_XLS = 27;
    public static final int FILE_PDF = 28;
    public static final int FILE_DB = 29;
    public static final int FILE_HTML = 30;
    public static final int FILE_XML = 31;
    public static final int FILE_WBD = 32;
    public static final int FILE_COMPRESS = 33;

    public static final int FILE_OFFICE = 34;
    public static final int FILE_DOCUMENT_ALL = 35;
    public static final int FILE_OTHER = 100;

    private static final NumberFormat NUMBERFORMAT = NumberFormat.getInstance();
    public static final String sLocalRoot = Environment.getExternalStorageDirectory().getAbsolutePath();

    public static List<FileInfo> listFiles(File file) {
        return listFiles(file, null);
    }

    public static List<FileInfo> listFiles(File file, Set<Integer> types) {
        MyLog.cdl("==listFiles==" + file);
        List<FileInfo> list = new ArrayList<>();
        if (file == null || !file.isDirectory()) {
            return list;
        }
        String[] fileList = file.list();
        if (fileList == null || fileList.length < 1) {
            MyLog.cdl("==listFiles=names == null=");
            return list;
        }
        MyLog.cdl("==listFiles=names ===" + fileList.length);
        for (String name : fileList) {
            File child = new File(file, name);
            if (types == null || types.isEmpty() || child.isDirectory()) {
                list.add(new FileInfo(child));
                continue;
            }
            for (int type : types) {
                if (isFileByType(child.getName(), type)) {
                    list.add(new FileInfo(child));
                    break;
                }
            }
        }
        return list;
    }

    public static void filterFiles(List<FileInfo> list, Set<Integer> types) {
        if (types == null || types.isEmpty()) {
            return;
        }
        Iterator<FileInfo> tor = list.iterator();
        while (tor.hasNext()) {
            FileInfo item = tor.next();
            if (item.isDirectory()) {
                continue;
            }
            boolean isMove = true;
            for (int type : types) {
                if (isFileByType(item.getName(), type)) {
                    isMove = false;
                    break;
                }
            }
            if (isMove) {
                tor.remove();
            }
        }
    }

    /**
     * 文件搜索 （模糊查找）
     *
     * @param fileOrDir 要指定搜索的文件或者目录
     * @param name      要搜索的文件名
     * @param fileType  文件类型过滤
     * @param filter    文件夹过滤
     */
    public static List<FileInfo> searchFiles(File fileOrDir, String name, int fileType, String... filter) {
        List<FileInfo> searchResult = new ArrayList<>();
        if (fileOrDir == null || !fileOrDir.exists()) {
            return searchResult;
        }
        if (fileOrDir.getName().toLowerCase().contains(name)) {
            searchResult.add(new FileInfo(fileOrDir));
        }
        if (!fileOrDir.isDirectory()) {
            return searchResult;
        }

        Queue<File> queue = new LinkedList<>();
        listDirFile(fileOrDir, queue, filter);
        File file;
        name = name.toLowerCase();
        while (!queue.isEmpty()) {
            file = queue.poll();
            if (file == null) {
                continue;
            }

            if (file.isDirectory()) {
                listDirFile(file, queue, filter);
            } else {
                if (isFileByType(file.getName(), fileType) && file.getName().toLowerCase().contains(name)) {
                    searchResult.add(new FileInfo(file));
                }
            }
        }
        return searchResult;
    }

    private static void listDirFile(File directory, Queue<File> queue, String... filter) {
        if (directory.isDirectory()) {
            if (filter.length > 0) {
                for (String path : filter) {
                    if (directory.getAbsolutePath().startsWith(path)) {
                        return;
                    }
                }
            }
            File[] files = directory.listFiles();
            if (files == null) {
                return;
            }
            for (File file : files) {
                queue.offer(file);
            }
        }
    }

    private static void checkDirectory(File directory) {
        if (!directory.exists()) {
            throw new IllegalArgumentException(directory + " does not exist");
        }
        if (!directory.isDirectory()) {
            throw new IllegalArgumentException(directory + " is not a directory");
        }
    }

    /**
     * @param fileName   文件名
     * @param type   {@link FileType}
     * @param type   file
     */
    private static boolean isFileByType(String fileName, int type) {
        if (fileName == null) {
            return false;
        }
        if (type == FileType.FILE_ALL) {
            return true;
        }
        switch (type) {
            case FileType.FILE_APK:
                return isApkFile(fileName);
            case FileType.FILE_IMAGE:
                if (isImageFile(fileName)) {
                    return true;
                }
                return isGifFile(fileName);
            case FileType.FILE_AUDIO:
                return isAudioFile(fileName);
            case FileType.FILE_VIDEO:
                return isVideoFile(fileName);
            case FileType.FILE_ARCHIVE:
                return isCompressFile(fileName);
            case FileType.FILE_OFFICE:
                return isOffice(fileName);
            case FileType.FILE_TEXT:
                if (isTextFile(fileName)) {
                    return true;
                }
                if (isHtmlFile(fileName)) {
                    return true;
                }
                if (isXmlFile(fileName)) {
                    return true;
                }
                return isScript(fileName);
            case FileType.FILE_WHITEBOARD:
                return isWBD(fileName);
        }
        return false;
    }


    public static int getFileType(String name) {
        if (name == null) {
            return FILE_OTHER;
        }
        if (isWBD(name)) return FILE_WBD;
        if (isImageFile(name)) return FILE_IMAGE;
        if (isGifFile(name)) return FILE_GIF;
        if (isWebpFile(name)) return FILE_WEBP;
        if (isAudioFile(name)) return FILE_AUDIO;
        if (isVideoFile(name)) return FILE_VIDEO;
        if (isOffice(name)) {
            return FILE_OFFICE;
        }
        if (isApkFile(name)) return FILE_APK;
        if (isTextFile(name)) return FILE_TEXT;
        if (isHtmlFile(name)) return FILE_HTML;
        if (isXmlFile(name)) return FILE_XML;
        if (isScript(name)) return FILE_SCRIPT;
        if (isExcel(name)) return FILE_XLS;
        if (isWord(name)) return FILE_WORD;
        if (isPPt(name)) return FILE_PPT;
        if (isPdf(name)) return FILE_PDF;
        if (isCompressFile(name)) return FILE_COMPRESS;
        return FILE_OTHER;
    }

    /**
     * 判断文件是否是图片文件
     * .jpg; .bmp; .eps; .mif; .miff; .png; .tif; .tiff; .svg; .wmf; .jpe; .jpeg; .dib; .ico; .tga; .cut; .pic
     *
     * @param name
     * @return
     */
    public static boolean isImageFile(String name) {
        name = name.toLowerCase();
        return name.endsWith(".png")
            || name.endsWith(".jpg")
            || name.endsWith(".jpeg")
            || name.endsWith(".webp")
            || name.endsWith(".bmp")
            || name.endsWith(".svg");
    }

    /**
     * 判断文件是否是webp图片文件
     * .webp
     *
     * @param name
     * @return
     */
    public static boolean isWebpFile(String name) {
        name = name.toLowerCase();
        return name.endsWith(".webp");
    }

    /**
     * 判断文件是否是gif图片文件
     * .gif
     *
     * @param name
     * @return
     */
    public static boolean isGifFile(String name) {
        name = name.toLowerCase();
        return name.endsWith(".gif");
    }

    /**
     * 判断文件是否是音频文件
     * .MP3; .AAC; .WAV; .WMA; .CDA; .FLAC; .M4A; .MID; .MKA; .MP2; .MPA; .MPC; .APE; .OFR; .OGG; .RA; .WV; .TTA; .AC3; .DTS
     * M4A,AC3，AMR,APE,FLAC,MID,MP3,OGG,RA,WAV,WMA,ACC,ACC+
     *
     * @param name
     * @return
     */
    public static boolean isAudioFile(String name) {
        name = name.toLowerCase();
        return name.endsWith(".mp3")
            || name.endsWith(".aac")
            || name.endsWith(".wav")
            || name.endsWith(".m4a")
            || name.endsWith(".mid")
            || name.endsWith(".ape")
            || name.endsWith(".ac3")
            || name.endsWith(".amr")
            || name.endsWith(".flac")
            || name.endsWith(".ra")
            || name.endsWith(".wma")
            || name.endsWith(".ogg")
            || name.endsWith(".midi")
            || name.endsWith(".mp2")
            || name.endsWith(".m4r")
            || name.endsWith(".acc+");
    }

    /**
     * 判断文件是否是视频文件
     * .AVI; .ASF; .WMV; .AVS; .FLV;.m4v .MKV; .MOV; .3GP; .MP4; .MPG; .MPEG; .DAT; .OGM; .VOB; .RM; .RMVB; .TS; .TP; .IFO; .NSV
     *
     * @param name
     * @return
     */
    public static boolean isVideoFile(String name) {
        name = name.toLowerCase();
        return name.endsWith(".avi")
            || name.endsWith(".ts")
            || name.endsWith(".tp")
            || name.endsWith(".wmv")
            || name.endsWith(".flv")
            || name.endsWith(".mkv")
            || name.endsWith(".mov")
            || name.endsWith(".3gp")
            || name.endsWith(".mp4")
            || name.endsWith(".mpg")
            || name.endsWith(".mpeg")
            || name.endsWith(".rm")
            || name.endsWith(".rmvb")
            || name.endsWith(".asf")
            || name.endsWith(".es")
            || name.endsWith(".m2t")
            || name.endsWith(".m2ts")
            || name.endsWith(".m4v");
    }

    /**
     * 判断文件是否是压缩文件
     * .rar*.zip*.cab*.arj*.lzh*.ace*.7-zip*.tar*.gzip*.uue*.bz2*.jar*.iso*.z
     *
     * @param name
     * @return
     */
    public static boolean isCompressFile(String name) {
        name = name.toLowerCase();
        return name.endsWith(".rar")
            || name.endsWith(".zip")
            || name.endsWith(".tar")
            || name.endsWith(".jar")
            || name.endsWith(".gzip")
            || name.endsWith(".7z")
            || name.endsWith(".tgz")
            || name.endsWith(".taz")
            || name.endsWith(".z")
            || name.endsWith(".gz");
    }

    /**
     * 判断文件是否是apk安装包
     *
     * @param name
     * @return
     */
    public static boolean isApkFile(String name) {
        name = name.toLowerCase();
        return name.endsWith(".apk");
    }

    /**
     * 判断文件是否是文本文件
     * .txt .sh .log .xml .java .c .cpp .mk .ini .inf .h
     *
     * @param name
     * @return
     */
    public static boolean isTextFile(String name) {
        name = name.toLowerCase();
        return name.endsWith(".txt")
            || name.endsWith(".prop")
            || name.endsWith(".conf")
            || name.endsWith(".inf")
            || name.endsWith(".log")
            || name.endsWith(".java")
            || name.endsWith(".c")
            || name.endsWith(".cpp")
            || name.endsWith(".mk")
            || name.endsWith(".h")
            || name.endsWith(".ini");
    }

    public static boolean isHtmlFile(String name) {
        name = name.toLowerCase();
        return name.endsWith(".html");
    }

    public static boolean isXmlFile(String name) {
        name = name.toLowerCase();
        return name.endsWith(".xml");
    }

    public static boolean isScript(String name) {
        name = name.toLowerCase();
        return name.endsWith(".sh") || name.endsWith(".rc");
    }

    public static boolean isExcel(String name) {
        name = name.toLowerCase();
        return name.endsWith(".xls") || name.endsWith(".xlsx");
    }

    public static boolean isWord(String name) {
        name = name.toLowerCase();
        return name.endsWith(".doc") || name.endsWith(".docx");
    }

    public static boolean isPPt(String name) {
        name = name.toLowerCase();
        return name.endsWith(".ppt") || name.endsWith(".pptx");
    }

    public static boolean isPdf(String name) {
        name = name.toLowerCase();
        return name.endsWith(".pdf");
    }

    public static boolean isOffice(String name) {
        name = name.toLowerCase();
        return name.endsWith(".doc")
            || name.endsWith(".docx")
            || name.endsWith(".ppt")
            || name.endsWith(".pptx")
            || name.endsWith(".pdf")
            || name.endsWith(".xls")
            || name.endsWith(".xlsx");
    }


    public static boolean isWBD(String name) {
        name = name.toLowerCase();
        return name.endsWith(".wbd");
    }

    /**
     * @param name df
     * @param def  df
     */
    public static String getMimeType(String name, String def) {
        if (name == null) {
            return def;
        }
        FileNameMap nameMap = URLConnection.getFileNameMap();
        String mineType = nameMap.getContentTypeFor(name);
        if (mineType == null) {
            return def;
        }
        return mineType;
    }

    public static String getName(String path) {
        if (path == null) {
            return null;
        }
        return path.substring(path.lastIndexOf('/') + 1);
    }

    public static String getFormatByte(long byteNumber) {
        return getFormatByte(byteNumber, 2);
    }

    /**
     * 1M = 1024k * 1024k
     * 对字节数进行相应的格式化，比如1024个字节=1k
     *
     * @return format string
     */
    public static String getFormatByte(long byteNumber, int digit) {
        if (byteNumber < KB) {
            return byteNumber + "B";
        }
        if (byteNumber < MB) {
            return formatDot(byteNumber * 1d / KB, digit) + "K";
        }
        if (byteNumber < GB) {
            return formatDot(byteNumber * 1d / MB, digit) + "M";
        }
        if (byteNumber < TB) {
            return formatDot(byteNumber * 1d / GB, digit) + "G";
        }
        if (byteNumber < PB) {
            return formatDot(byteNumber * 1d / TB, digit) + "T";
        }
        if (byteNumber < EB) {
            return formatDot(byteNumber * 1d / PB, digit) + "P";
        }
        return formatDot(byteNumber * 1d / EB, digit) + "E";

    }

    /**
     * 1M = 1000k * 1000k
     *
     * @return string
     */
    public static String getFormatByteFor1000(long byteNumber, int digit) {
        if (byteNumber < KB_1) {
            return byteNumber + "B";
        }
        if (byteNumber < MB_1) {
            return formatDot(byteNumber * 1d / KB_1, digit) + "K";
        }
        if (byteNumber < GB_1) {
            return formatDot(byteNumber * 1d / MB_1, digit) + "M";
        }
        if (byteNumber < TB_1) {
            return formatDot(byteNumber * 1d / GB_1, digit) + "G";
        }
        if (byteNumber < PB_1) {
            return formatDot(byteNumber * 1d / TB_1, digit) + "T";
        }
        if (byteNumber < EB_1) {
            return formatDot(byteNumber * 1d / PB_1, digit) + "P";
        }
        return formatDot(byteNumber * 1d / EB_1, digit) + "E";

    }

    /**
     * 对浮点数保留digit位小数点，直接截取，不进行四舍五入 对于整数则不进行处理，保留原数
     *
     * @param number 输入的浮点数
     * @param digit  要保留的小数点位数
     * @return
     */
    private static String toFormatDot(double number, int digit) {
        NUMBERFORMAT.setMaximumFractionDigits(digit);
        if (NUMBERFORMAT.getRoundingMode() != RoundingMode.DOWN) {
            NUMBERFORMAT.setRoundingMode(RoundingMode.DOWN);
        }
        return NUMBERFORMAT.format(digit);
    }

    /**
     * 四舍五入
     *
     * @param number 数字
     * @param digit  小数点位数
     */
    private static String formatDot(double number, int digit) {
        NUMBERFORMAT.setMaximumFractionDigits(digit);
        if (NUMBERFORMAT.getRoundingMode() != RoundingMode.HALF_EVEN) {
            NUMBERFORMAT.setRoundingMode(RoundingMode.HALF_EVEN);
        }
        return NUMBERFORMAT.format(number);
    }

    public static void sync() throws Exception {
        Process process = Runtime.getRuntime().exec("sync");
        int code = process.waitFor();
    }

}

